/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.smart.service.search;

import com.smart.builder.entity.BuilderEntityHotel;
import com.smart.builder.xml.BuilderSummaryHotelType;
import com.smart.hotelsmart.SearchHotelRequestType;
import com.smart.hotelsmart.SearchHotelResponseType;
import com.smart.hotelsmart.SummaryHotelType;
import com.smart.persistence.entity.Destination;
import com.smart.persistence.entity.Hotel;
import com.smart.persistence.service.SmartBasicCrudDAO;
import com.smart.service.util.Logging;
import com.smart.service.util.UtilDate;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.xml.datatype.XMLGregorianCalendar;

/**
 * 
 * @author arthur
 */
public class SearchHotelService {

	private static final Logging LOGGER = Logging
			.getLogger(SearchHotelService.class.getName());

	private SearchWebHotelService search = new SearchWebHotelService();

	

	private void loadListSummaryHotelTypeFormDestination(
			List<SummaryHotelType> listSummaryHotelType, Destination destination) {
		LOGGER.debug("loadListSummaryHotelTypeFormDestination");
		assert destination != null;
		assert destination.getHoteis() != null;
		assert listSummaryHotelType != null;
		List<Hotel> hotels = destination.getHoteis();
		for (Hotel hotel : hotels) {
			SummaryHotelType summary = new BuilderSummaryHotelType().setHotel(hotel).setDestination(destination).getSummaryHotelType();
			listSummaryHotelType.add(summary);
		}
	}

	private void updateDestinationName(Destination destination, String name) {
		LOGGER.debug("updateDestinationName");
		assert destination != null;
		if (destination.getName() == null) {
			destination.setName("#" + name.replaceAll("\\W\\W", " ") + "#");
		} else {
			destination.setName(destination.getName() + "#"
					+ name.replaceAll("\\W\\W", " ") + "#");
		}
		updateDestination(destination);
	}

	private void updateDestination(Destination destination) {
		assert destination.getId() != 0;
		EntityManager em = SmartBasicCrudDAO.getInstance().getEntityManagerDAO();
		EntityTransaction et = em.getTransaction();
		try {
			et.begin();
			em.merge(destination);
			et.commit();
		} catch (Exception e) {
			et.rollback();
			throw new RuntimeException(e);
		}

	}

	private Destination createDestination(long codDestination, String name) {
		LOGGER.debug("createDestination");
		Destination destination = new Destination();
		destination.setCodDestination(codDestination);
		destination.setName("#" + name.replaceAll("\\W\\W", " ") + "#");
		EntityManager em = SmartBasicCrudDAO.getInstance().getEntityManagerDAO();
		EntityTransaction et = em.getTransaction();
		try {
			et.begin();
			em.persist(destination);
			et.commit();
		} catch (Exception e) {
			et.rollback();
			throw new RuntimeException(e);
		}
		return SmartBasicCrudDAO.getInstance().consultaQuerySingle(em,
				Destination.class, Destination.findByCodDestination,
				codDestination);
	}

	private long hasDestination(List<Map<String, String>> listHotel) {
		long codeDest = 0;
		for (int i = 0; i < listHotel.size(); i++) {
			Map<String, String> map = listHotel.get(i);
			String dest = map.get(SearchWebHotelService._destinationId);
			if (dest != null) {
				assert dest.matches("\\d+");
				codeDest = new Long(dest).longValue();
				break;
			}
		}
		return codeDest;

	}

	private Destination checkDestination(long codeDest) {
		LOGGER.debug("checkDestination");
		Destination destination = null;
		if (codeDest != 0) {
			destination = SmartBasicCrudDAO.getInstance().consultaQuerySingle(
					SmartBasicCrudDAO.getInstance().getEntityManagerDAO(), Destination.class,
					Destination.findByCodDestination, codeDest);
		}
		return destination;
	}

	private List<Hotel> createListHotelFormMap(
			List<Map<String, String>> listHotel, Destination entityDest) {
		LOGGER.debug("createListHotelTypeFormMap");
		// int codeDestination = 0;
		List<Hotel> hotels = new ArrayList<Hotel>();
		EntityManager em = SmartBasicCrudDAO.getInstance().getEntityManagerDAO();
		for (Map<String, String> map : listHotel) {
			Hotel hotel = new BuilderEntityHotel(getCodeHotel(map), em).setMap(map).setDestination(entityDest).getHotel();
			hotels.add(hotel);
		}
		return hotels;
	}
	
	private int getCodeHotel(Map<String, String> map) {
		int codeH = 0;
		assert map.containsKey(SearchWebHotelService._codeHotel) : "no contains Key "
				+ SearchWebHotelService._codeHotel;
		String codeHotel = map.get(SearchWebHotelService._codeHotel);
		assert codeHotel.matches("\\d+") : "no matches \\d+";
		codeH = new Integer(codeHotel).intValue();
		return codeH;
	}

	/*
	 * private int loadListSummaryHotelTypeFormMap(List<SummaryHotelType> list,
	 * List<Map<String, String>> listHotel) {
	 * LOGGER.debug("loadListSummaryHotelTypeFormMap"); int codeDestination = 0;
	 * for (Map<String, String> map : listHotel) { String dest =
	 * map.get(SearchHotelService._destinationId); assert dest.matches("\\d+");
	 * int codeDest = new Integer(dest).intValue(); if(codeDestination == 0){
	 * codeDestination = codeDest; }else{ assert codeDestination == codeDest; }
	 * SummaryHotelType summary = null; String codeHotel =
	 * map.get(SearchHotelService._codeHotel); assert codeHotel.matches("\\d+");
	 * int codeH = new Integer(codeHotel).intValue(); Hotel hotel =
	 * SmartBasicCrudDAO
	 * .getInstance().consultaQuerySingle(SmartBasicCrudDAO.getEntityManager(),
	 * Hotel.class, Hotel.findByCodeHotel, codeH); assert hotel == null; summary
	 * = createSummaryHotelTypeFromMap(map); list.add(summary); } return
	 * codeDestination; }
	 */
	private void saveHotels(List<Hotel> list) {
		LOGGER.debug("saveHotels");
		assert list != null;
		EntityManager em = SmartBasicCrudDAO.getInstance().getEntityManagerDAO();
		EntityTransaction et = em.getTransaction();
		try {
			et.begin();
			for (Hotel hotel : list) {
				saveHotel(em, hotel);
			}
			et.commit();
		} catch (Exception e) {
			if(et.isActive()){
				et.rollback();	
			}
			throw new RuntimeException(e);
		}
	}

	private void saveHotel(EntityManager em, Hotel hotel) {
		LOGGER.debug("saveHotel " + hotel);
		if (hotel.getId() == 0) {
			em.persist(hotel);
		} else {
			em.merge(hotel);
		}
	}

	/*
	 * private void createHotels(Destination destination, List<SummaryHotelType>
	 * list){ LOGGER.debug("createHotels"); assert destination != null; assert
	 * destination.getId() != 0; assert list != null; EntityManager em =
	 * SmartBasicCrudDAO.getEntityManager(); EntityTransaction et =
	 * em.getTransaction(); try{ et.begin(); for (SummaryHotelType
	 * summaryHotelType : list) { Hotel hotel =
	 * createHotelFromSummary(summaryHotelType);
	 * hotel.getDestinations().add(destination); em.persist(hotel); }
	 * et.commit(); }catch(Exception e){ et.rollback(); throw new
	 * RuntimeException(e); } }
	 */

	public SearchHotelResponseType getSearchAvailableHotels(
			SearchHotelRequestType body) {
		LOGGER.debug("getSearchAvailableHotels");
		assert body != null;
		LOGGER.debug("getHoteisDisponiveis " + body);
		SearchHotelResponseType response = new SearchHotelResponseType();
		try {
			String nameDestination = body.getDestination().replaceAll("\\W\\W",
					" ");
			List<Destination> destinations = SmartBasicCrudDAO
					.getInstance()
					.consultaQueryList(SmartBasicCrudDAO.getInstance().getEntityManagerDAO(), Destination.class,
							Destination.findByName, "#" + nameDestination + "#");
			if (!destinations.isEmpty()) {
				assert destinations.size() == 1;
				Destination destination = destinations.get(0);
				loadListSummaryHotelTypeFormDestination(
						response.getSummaryHotel(), destination);
			} else {
				XMLGregorianCalendar arrival = body.getArrival();
				XMLGregorianCalendar departure = body.getDeparture();
				List<Map<String, String>> listHotel = search.searchHotel(
						nameDestination, UtilDate.formatDateGregorianCalendar(arrival),
						UtilDate.formatDateGregorianCalendar(departure));
				search.end();
				assert listHotel != null : "listHotel is null for Destination = "
						+ nameDestination;
				assert !listHotel.isEmpty() : "listHotel is Empty for Destination = "
						+ nameDestination;
				long codeDestination = hasDestination(listHotel);
				Destination destination = null;
				if (codeDestination != 0) {
					destination = checkDestination(codeDestination);
					if (destination == null) {
						destination = createDestination(codeDestination,
								nameDestination);
					} else {
						updateDestinationName(destination, nameDestination);
					}
				} else {
					destination = createDestination(codeDestination,
							nameDestination);
					destination.setCodDestination(destination.getId());
					codeDestination = destination.getId();
					updateDestination(destination);
				}
				List<Hotel> hotels = createListHotelFormMap(listHotel,
						destination);
				saveHotels(hotels);
				destination = checkDestination(codeDestination);
				assert destination != null;
				assert destination.getHoteis() != null;
				assert destination.getHoteis().size() != 0;
				assert destination.getHoteis().size() == hotels.size();
				loadListSummaryHotelTypeFormDestination(
						response.getSummaryHotel(), destination);
			}
		} catch (Exception e) {
			LOGGER.error("getHoteisDisponiveis", e);
			throw new RuntimeException(e);
		}
		return response;
	}

	private Hotel findHoteByCodHotel(int codHotel) {
		LOGGER.debug("findHoteByCodHotel");
		Hotel hotel = SmartBasicCrudDAO.getInstance().consultaQuerySingle(
				SmartBasicCrudDAO.getInstance().getEntityManagerDAO(),
				Hotel.class, Hotel.findByCodeHotel, codHotel);
		return hotel;
	}




}
